<template>
  <div id="nav">
    <h1 style="text-align: center">欢迎来到数字华容道</h1>
    <el-form :inline="true" :model="formInline" style="margin-left: 30%">
      <el-form-item label="行">
        <el-input v-model="formInline.row" placeholder="请输入行数"></el-input>
      </el-form-item>
      <el-form-item label="列">
        <el-input v-model="formInline.col" placeholder="请输入列数"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" round @click="beginGame">开始游戏</el-button>
      </el-form-item>
    </el-form>
    <div class="flex-container">
      <div>
        <h3>初始数码</h3>
        <div class="wall-container" :style="wraperContainerStyle">
          <!--列表循环需加:key="唯一标识" 唯一标识可以是item里面id index等-->
          <template v-for="(i,index_i) in formInline.row * formInline.col" :key="index_i">
            <number-block :value="initArray[index_i]">{{initArray[index_i]}}</number-block>
          </template>
        </div>
      </div>
      <div>
        <h3>目标数码</h3>
        <div class="wall-container" :style="wraperContainerStyle">
          <!--列表循环需加:key="唯一标识" 唯一标识可以是item里面id index等-->
          <template v-for="(i,index_i) in formInline.row * formInline.col" :key="index_i">
            <number-block :value="targetArray[index_i]">{{targetArray[index_i]}}</number-block>
          </template>
        </div>
      </div>
    </div>
    <div class="flex-container" style="margin-top:20px">
      <div style="margin-top: 40px">
        <div class="wall-container" :style="wraperContainerStyle">
          <!--列表循环需加:key="唯一标识" 唯一标识可以是item里面id index等-->
          <template v-for="(i,index_i) in formInline.row * formInline.col" :key="i">
            <number-block :value="items[index_i]" @click="changeNumber(index_i)">{{items[index_i]}}</number-block>
          </template>
        </div>
        <el-button type="success" round style="margin-top: 20px" @click="restart">重新开始</el-button>
      </div>
      <div style="text-align: center">
        <el-button type="text" @click="drawer= !drawer" >查看答案</el-button>
        <div v-if="drawer">
          <div class="wall-container" :style="wraperContainerStyle">
            <!--列表循环需加:key="唯一标识" 唯一标识可以是item里面id index等-->
            <template v-for="(i,index_i) in formInline.row * formInline.col" :key="i">
              <number-block :value="resultArray[index_i]">{{resultArray[index_i]}}</number-block>
            </template>
          </div>
          <el-button-group style="margin-top: 20px;">
            <el-button type="primary" :icon="ArrowLeft" v-if="emptyIndexOfResult != 0" @click="lastStep">上一步</el-button>
            <el-button type="primary" :icon="ArrowRight" style="margin-left: 20px" v-if="emptyIndexOfResult != arrOfResultEmpty.length-1" @click="nextStep">下一步</el-button>
          </el-button-group>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import NumberBlock from './components/NumberBlock'
import { ElMessageBox } from 'element-plus'
export default {
  name: 'app',
  components: {
    NumberBlock
  },
  data () {
    return {
      items: [],
      initArray: [], // 初始数码
      targetArray: [], // 目标数码
      emptyIndex: '',
      formInline: {
        row: 3,
        col: 4
      },
      index: '',
      drawer: false,
      resultArray: [], // 答案
      emptyIndexOfResult: 0, // 当前答案的空格索引位置
      arrOfResultEmpty: []
    }
  },
  computed: {
    wraperContainerStyle () {
      const width = 62 * this.formInline.col + 'px'
      const height = 62 * this.formInline.row + 'px'
      return { width, height }
    }
  },
  methods: {
    changeNumber (index) {
      this.index = index
      if (Math.abs(index - this.emptyIndex) === 1 || Math.abs(index - this.emptyIndex) === parseInt(this.formInline.col)) {
        const number = this.items[index]
        this.items[index] = 0
        this.items[this.emptyIndex] = number
        this.emptyIndex = index
        this.checkGameOver()
      }
    },
    beginGame () {
      this.initArray = this.shuffle([...new Array(this.formInline.col * this.formInline.row).keys()])
      this.items = JSON.parse(JSON.stringify(this.initArray))
      this.emptyIndex = this.calEmptyIndex(this.items)
      this.targetArray = this.generteTargetArray(this.initArray, parseInt(this.formInline.col), this.emptyIndex, 4)
      this.resultArray = JSON.parse(JSON.stringify(this.initArray))
      this.emptyIndexOfResult = 0
    },
    // 打乱一个数组
    shuffle (arr) {
      for (var i = arr.length - 1; i >= 0; i--) {
        var randomIndex = Math.floor(Math.random() * (i + 1))
        var itemAtIndex = arr[randomIndex]
        arr[randomIndex] = arr[i]
        arr[i] = itemAtIndex
      }
      return arr
    },
    calEmptyIndex (arr) {
      for (let i = 0; i < arr.length; i++) {
        if (arr[i] === 0) {
          return i
        }
      }
    },
    generteTargetArray (arr, col, emptyIndex, n) {
      var targetArray = JSON.parse(JSON.stringify(arr))
      var lastEmptyIndex = -1
      var curEmptyIndex = emptyIndex
      var arrOfResultEmpty = []
      arrOfResultEmpty.push(curEmptyIndex)
      for (let i = 0; i < n; i++) {
        var flag = true
        while (flag === true) {
          const random = Math.floor(Math.random() * 4)
          switch (random) {
            case 0: // 左移
              if (curEmptyIndex % col >= 1 && curEmptyIndex - 1 !== lastEmptyIndex) {
                const temp = targetArray[curEmptyIndex - 1]
                targetArray[curEmptyIndex - 1] = targetArray[curEmptyIndex]
                targetArray[curEmptyIndex] = temp
                lastEmptyIndex = curEmptyIndex
                curEmptyIndex -= 1
                flag = false
              }
              break
            case 1: // 右移
              if (curEmptyIndex % col < col - 1 && curEmptyIndex + 1 !== lastEmptyIndex) {
                const temp = targetArray[curEmptyIndex + 1]
                targetArray[curEmptyIndex + 1] = targetArray[curEmptyIndex]
                targetArray[curEmptyIndex] = temp
                lastEmptyIndex = curEmptyIndex
                curEmptyIndex += 1
                flag = false
              }
              break
            case 2:
              if (curEmptyIndex >= col && curEmptyIndex - col !== lastEmptyIndex) {
                const temp = targetArray[curEmptyIndex - col]
                targetArray[curEmptyIndex - col] = targetArray[curEmptyIndex]
                targetArray[curEmptyIndex] = temp
                lastEmptyIndex = curEmptyIndex
                curEmptyIndex -= col
                flag = false
              }
              break
            case 3:
              if (curEmptyIndex < arr.length - col && curEmptyIndex + col !== lastEmptyIndex) {
                const temp = targetArray[curEmptyIndex + col]
                targetArray[curEmptyIndex + col] = targetArray[curEmptyIndex]
                targetArray[curEmptyIndex] = temp
                lastEmptyIndex = curEmptyIndex
                curEmptyIndex += col
                flag = false
              }
              break
          }
        }
        arrOfResultEmpty.push(curEmptyIndex)
      }
      this.arrOfResultEmpty = arrOfResultEmpty
      return targetArray
    },
    checkGameOver () {
      if (JSON.stringify(this.items) === JSON.stringify(this.targetArray)) {
        ElMessageBox.alert('太棒了，恭喜过关', '提示', {
          confirmButtonText: '确定',
          callback: (action) => {
            this.beginGame()
          }
        })
      }
    },
    // 重新开始游戏，将当前数码恢复到和初始数码一致
    restart () {
      this.items = JSON.parse(JSON.stringify(this.initArray))
      this.emptyIndex = this.calEmptyIndex(this.items)
    },
    lastStep () {
      const temp = this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult - 1]]
      this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult - 1]] = this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult]]
      this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult]] = temp
      this.emptyIndexOfResult -= 1
    },
    nextStep () {
      const temp = this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult + 1]]
      this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult + 1]] = this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult]]
      this.resultArray[this.arrOfResultEmpty[this.emptyIndexOfResult]] = temp
      this.emptyIndexOfResult += 1
    }
  },
  created () {
    this.beginGame()
  }
}
</script>

<style>
body {
  background-color: bisque;
}

.wall-container{
  background-color: #f0f0f0;
  display: flex;      /*弹性布局*/
  flex-wrap: wrap;    /*子容器宽度超出父容器宽度，会换行*/
  margin-top: 15px;
  padding: 5px;
  cursor: pointer;        /*鼠标的图形形状*/
  -moz-user-select: none;
  user-select: none;    /*控制页面的文字不能被选中*/
  -webkit-user-select: none; /*禁止用户进行复制.选择*/
}
.flex-container{
  margin-left: 30%;
  display: flex;
  gap:100px;
  text-align: center;
}
</style>
